<template>
  <div class="chart-wrapper">
    <canvas ref="chartCanvas"></canvas>
  </div>
</template>

<script setup>
import { ref, onMounted, watch, onBeforeUnmount } from 'vue';

// 定义 props
const props = defineProps({
  data: {
    type: Array,
    required: true,
  },
  options: {
    type: Object,
    default: () => ({}),
  },
});

// 默认配置
const defaultOptions = {
  lineColor: '#00f2fe', // 折线颜色
  pointColor: '#ffffff', // 数据点颜色（白色）
  backgroundColor: ['#1e3c72', '#2a5298'], // 背景渐变色
  axisColor: ['#4facfe', '#00f2fe'], // 轴线渐变色
  gridColor: 'rgba(255, 255, 255, 0.1)', // 网格线颜色
  labelColor: '#fff', // 数据标签颜色
  topPadding: 30, // 顶部留白，确保标签显示
  bottomPadding: 20, // 底部留白，确保刻度线 0 不紧贴底部
  pointRadius: 5, // 数据点半径
  lineWidth: 2, // 折线宽度
  valueOffset: 10, // 数值标签与点的垂直偏移量
  sidePadding: 40, // 左右两侧的留白距离
  startOffset: 20, // 第一个点距离左边刻度线的距离
};

// 合并配置
const chartOptions = {
  ...defaultOptions,
  ...props.options,
};

// 引用 canvas 元素
const chartCanvas = ref(null);
let ctx = null; // canvas 上下文

// 初始化 canvas
const initCanvas = () => {
  if (chartCanvas.value) {
    const parent = chartCanvas.value.parentElement;
    chartCanvas.value.width = parent.clientWidth; // 宽度充满父容器
    chartCanvas.value.height = parent.clientHeight; // 高度充满父容器
    ctx = chartCanvas.value.getContext('2d');
    renderChart();
  }
};

// 绘制渐变背景
const drawBackground = () => {
  const { width, height, backgroundColor } = chartOptions;
  const gradient = ctx.createLinearGradient(0, 0, 0, height);
  gradient.addColorStop(0, backgroundColor[0]);
  gradient.addColorStop(1, backgroundColor[1]);
  ctx.fillStyle = gradient;
  ctx.fillRect(0, 0, width, height);
};

// 绘制网格线
const drawGridLines = () => {
  const { width, height, gridColor, topPadding, bottomPadding, sidePadding } = chartOptions;
  const maxValue = Math.max(...props.data);
  const step = (height - topPadding - bottomPadding) / 5; // 网格线间距

  ctx.strokeStyle = gridColor;
  ctx.lineWidth = 0.5;

  // 水平网格线
  for (let i = 0; i <= 5; i++) {
    const y = height - bottomPadding - i * step; // 从底部开始计算
    ctx.beginPath();
    ctx.moveTo(sidePadding, y); // 左侧留白
    ctx.lineTo(width - sidePadding, y); // 右侧留白
    ctx.stroke();
  }
};

// 绘制轴线和标签
const drawAxes = () => {
  const { width, height, axisColor, labelColor, topPadding, bottomPadding, axisLineWidth, sidePadding } = chartOptions;
  const maxValue = Math.max(...props.data);

  // 绘制 Y 轴
  const yAxisGradient = ctx.createLinearGradient(0, topPadding, 0, height - bottomPadding);
  yAxisGradient.addColorStop(0, axisColor[0]);
  yAxisGradient.addColorStop(1, axisColor[1]);
  ctx.strokeStyle = yAxisGradient;
  ctx.lineWidth = axisLineWidth;
  ctx.beginPath();
  ctx.moveTo(sidePadding, topPadding); // 左侧留白
  ctx.lineTo(sidePadding, height - bottomPadding); // 底部留白
  ctx.stroke();

  // 绘制 X 轴（渐变色）
  const xAxisGradient = ctx.createLinearGradient(0, height - bottomPadding, width, height - bottomPadding);
  xAxisGradient.addColorStop(0, axisColor[0]);
  xAxisGradient.addColorStop(1, axisColor[1]);
  ctx.strokeStyle = xAxisGradient;
  ctx.beginPath();
  ctx.moveTo(sidePadding, height - bottomPadding); // 左侧留白
  ctx.lineTo(width - sidePadding, height - bottomPadding); // 右侧留白
  ctx.stroke();

  // 绘制 Y 轴标签
  ctx.fillStyle = labelColor;
  ctx.font = '12px Arial';
  ctx.textAlign = 'right';
  for (let i = 0; i <= 5; i++) {
    const value = (maxValue / 5) * i;
    const y = height - bottomPadding - (height - topPadding - bottomPadding) / 5 * i;
    ctx.fillText(value.toFixed(0), sidePadding - 10, y + 4); // 左侧留白
  }
};

// 绘制折线
const drawLine = () => {
  const { width, height, lineColor, pointColor, topPadding, bottomPadding, pointRadius, lineWidth, valueOffset, sidePadding, startOffset } = chartOptions;
  const maxValue = Math.max(...props.data);
  const scale = (height - topPadding - bottomPadding) / maxValue; // 考虑顶部和底部留白
  const step = (width - 2 * sidePadding - startOffset) / (props.data.length - 1); // 数据点间距（考虑左右留白和起始偏移）

  ctx.strokeStyle = lineColor;
  ctx.lineWidth = lineWidth;
  ctx.beginPath();

  props.data.forEach((value, index) => {
    const x = sidePadding + startOffset + index * step; // 左侧留白 + 起始偏移
    const y = height - bottomPadding - value * scale; // 从底部开始绘制，考虑底部留白

    if (index === 0) {
      ctx.moveTo(x, y); // 第一个点
    } else {
      ctx.lineTo(x, y); // 连接后续点
    }
  });

  ctx.stroke();

  // 绘制数据点和数值标签
  ctx.fillStyle = pointColor; // 使用白色填充数据点
  ctx.font = '12px Arial';
  ctx.textAlign = 'center';
  props.data.forEach((value, index) => {
    const x = sidePadding + startOffset + index * step; // 左侧留白 + 起始偏移
    const y = height - bottomPadding - value * scale; // 从底部开始绘制，考虑底部留白

    // 绘制数据点
    ctx.beginPath();
    ctx.arc(x, y, pointRadius, 0, Math.PI * 2);
    ctx.fill();

    // 绘制数值标签
    ctx.fillStyle = chartOptions.labelColor;
    ctx.fillText(value.toFixed(0), x, y - valueOffset); // 在点上方显示数值
  });
};

// 渲染图表
const renderChart = () => {
  if (!chartCanvas.value) return;

  // 清空画布
  ctx.clearRect(0, 0, chartCanvas.value.width, chartCanvas.value.height);

  // 更新配置中的宽度和高度
  chartOptions.width = chartCanvas.value.width;
  chartOptions.height = chartCanvas.value.height;

  // 绘制背景、网格线、轴线和折线
  drawBackground();
  drawGridLines();
  drawAxes();
  drawLine();
};

// 监听数据变化
watch(
    () => props.data,
    () => {
      renderChart();
    },
    { deep: true }
);

// 组件挂载时初始化
onMounted(() => {
  initCanvas();
  window.addEventListener('resize', initCanvas); // 监听窗口大小变化
});

// 组件卸载时移除监听器
onBeforeUnmount(() => {
  window.removeEventListener('resize', initCanvas);
});
</script>

<style scoped>
.chart-wrapper {
  width: 100%;
  height: 100%;
}
</style>